package com.leyou.user.userService.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.RegexUtils;
import com.leyou.pojo.dto.UserDto;
import com.leyou.user.entity.User;
import com.leyou.user.mapper.UserMapper;
import com.leyou.user.userService.UserService;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

import static com.leyou.common.constants.MQConstants.ExchangeConstants.SMS_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.VERIFY_CODE_KEY;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    private static final String PHONE_CODE = "user:verfriy:phone:";

    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;
    /**
     * 根据用户名和密码查询用户
     * @param username
     * @param password
     * @return
     */
    @Override
    public UserDto queryUserByNameAndPsw(String username, String password) {
        //设置查询条件
//        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq(StringUtils.isNotBlank(username),"username", username).eq(StringUtils.isNotBlank(password),"password",password);
//        User user = getOne(queryWrapper);
//        if(user==null){
//            throw  new LyExceptions("用户或密码错误",400);
//        }
//        //密码不要返回
//        user.setPassword(null);
        //因为密码加密后每次都不一样，所以先查询用户
        User user = query().eq("username", username).one();
        //如果用户为空，则抛出异常
        if(user==null){
            throw new LyException("用户名或密码错误",400);
        }
        //进行密码匹配
        boolean matches = passwordEncoder.matches(password, user.getPassword());
        if(!matches){
            throw new LyException("用户名或密码错误",400);
        }
        //转换成dto
        UserDto userDto = new UserDto(user);
        return userDto;
    }

    /**
     * 注册用户
     * @param username
     * @param password
     * @param phone
     * @param code
     */
    @Override
    @Transactional
    public void registerUser(String username,
                             String password,
                             String phone, String code) {
        //先比较验证码是否正确
        String s = redisTemplate.opsForValue().get(PHONE_CODE + phone);
        if(StringUtils.isEmpty(s)){
            throw new LyException("验证码已过期，请重新获取",400);
        }
        if(!s.equals(code)){
            throw new LyException("验证码错误，请重新输入",400);
        }
        //查询用户是否存在，存在不能注册
//        List<User> list = query().eq("username", username).list();
//        if(!CollectionUtils.isEmpty(list)){
//            throw new LyExceptions("用户名已存在请重新输入", 400);
//        }
        //已校验过
//        if(paramIsExist(username, 1)){
//            throw new LyExceptions("用户名已存在请重新输入", 400);
//        }
//        if(paramIsExist(phone, 2)){
//            throw new LyExceptions("手机号已存在请重新输入", 400);
//        }
        //校验用户数据格式是否正确，利用hibernate validator 这个框架金进行校验，springboot集成了这个框架
        //密码加密
        String encodePassword = passwordEncoder.encode(password);
        //注册
        baseMapper.saveUser(username,encodePassword,phone);

    }

    /**
     * 发送短信验证码
     * @param phone
     */
    @Override
    public void sendSms(String phone) {
        //判断手机号是否正确
        if(!RegexUtils.isPhone(phone)){
            throw new LyException("手机号格式有误",400);
        }
        //向mq发送信息
        HashMap<String, String> map = new HashMap<>();
        map.put("phone",phone);
        String code = RandomStringUtils.randomNumeric(6);
        //将code放入redis，同时设置失效时间
//        redisTemplate.opsForValue().set(PHONE_CODE+phone,code);
//        redisTemplate.expire(PHONE_CODE+phone,1, TimeUnit.MINUTES);
        redisTemplate.opsForValue().set(PHONE_CODE+phone,code,5,TimeUnit.MINUTES);
        map.put("code", code);
        amqpTemplate.convertAndSend(SMS_EXCHANGE_NAME,VERIFY_CODE_KEY,map);
    }

    /**
     * 判断数据类型是否存在
     * @param data
     * @param type
     */
    @Override
    public Boolean paramIsExist(String data, Integer type) {
        //健壮性处理
        if(1!=type && 2!=type){
            throw new LyException("参数有误",400);
        }
        //判断，如果type是1，查询用户，如果type是2，查询手机号
//        if(1==type){
//            List<User> list = query().eq("username", data).list();
//            if(!CollectionUtils.isEmpty(list)){
//               return true;
//            }
//
//        }
//
//        if(2==type){
//            List<User> list = query().eq("phone", data).list();
//            if(!CollectionUtils.isEmpty(list)){
//                return true;
//            }
//        }
        //相比于查对象，查行数更快
        Integer count = query().eq(type==1,"username", data)
                .eq(type==2,"phone", data)
                .count();
        return count == 1;
    }


}
